package com.gengzp.system.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.gengzp.common.enums.YesNoEnum;
import com.gengzp.common.model.log.entity.SysOperationLog;
import com.gengzp.common.model.log.entity.SysTraceLog;
import com.gengzp.common.model.log.req.CreateOperationLogReq;
import com.gengzp.common.model.log.req.CreateTraceLogReq;
import com.gengzp.common.model.log.req.PageOperationLogReq;
import com.gengzp.common.model.log.req.SearchTraceLogReq;
import com.gengzp.common.model.log.resp.ListTraceLogResp;
import com.gengzp.common.model.log.resp.PageOperationLogResp;
import com.gengzp.common.model.pagination.resp.PaginationResponse;
import com.gengzp.common.model.user.entity.SysUser;
import com.gengzp.common.utils.DateUtils;
import com.gengzp.common.utils.JsonUtils;
import com.gengzp.system.facade.SysUserFacade;
import com.gengzp.system.mapper.SysOperationLogMapper;
import com.gengzp.system.mapper.SysTraceLogMapper;
import com.gengzp.system.service.SysLogService;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.gengzp.common.constants.DatePatternConstants.YMD_HMS_MS_PATTERN;

/**
 * @ClassName SysLogServiceImpl
 * @Description 系统日志服务层实现类
 * @Author gengzp
 * @Date 2025/9/28 14:57
 */
@Service
public class SysLogServiceImpl implements SysLogService {

    private static final Logger logger = LoggerFactory.getLogger(SysLogServiceImpl.class);

    @Autowired
    private SysTraceLogMapper sysTraceLogMapper;

    @Autowired
    private SysOperationLogMapper sysOperationLogMapper;

    @Autowired
    private SysUserFacade sysUserFacade;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createSysTraceLog(CreateTraceLogReq req) {
        SysTraceLog sysTraceLog = new SysTraceLog();
        sysTraceLog.setTraceId(req.getTraceId());
        sysTraceLog.setServiceName(req.getServiceName());
        sysTraceLog.setLogContent(JsonUtils.toJsonString(req.getLogContents()));
        sysTraceLog.setIsDeleted(YesNoEnum.NO.getCode());
        sysTraceLogMapper.insertSysTraceLog(sysTraceLog);
    }

    @Override
    public List<ListTraceLogResp> listTraceLogs(SearchTraceLogReq req) {
        List<SysTraceLog> sysTraceLogs = sysTraceLogMapper.selectSysTraceLogsByTraceId(req.getTraceId());
        if (CollectionUtils.isEmpty(sysTraceLogs)) {
            return Collections.emptyList();
        }

        List<ListTraceLogResp> result = Lists.newArrayList();
        for (SysTraceLog sysTraceLog : sysTraceLogs) {
            if (StringUtils.isBlank(sysTraceLog.getLogContent())) {
                continue;
            }

            for (String logContent : JsonUtils.parseObject(sysTraceLog.getLogContent(),
                    new TypeReference<List<String>>() {
                    })) {
                ListTraceLogResp resp = new ListTraceLogResp();
                resp.setServiceName(sysTraceLog.getServiceName());
                resp.setLogContent(logContent);
                result.add(resp);
            }
        }

        // 根据调用时间升序排序
        result.sort(Comparator.comparing(o ->
                DateUtils.Str2Date(o.getLogContent().substring(1, 24).replace(".", ":"),
                        YMD_HMS_MS_PATTERN)));

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createSysOperationLog(CreateOperationLogReq req) {
        SysOperationLog sysOperationLog = new SysOperationLog();
        sysOperationLog.setTraceId(req.getTraceId());
        sysOperationLog.setUri(req.getUri());
        sysOperationLog.setParam(req.getParam());
        sysOperationLog.setStartTime(req.getStartTime());
        sysOperationLog.setConsumeTime(req.getConsumeTime());
        sysOperationLog.setRequestDescription(req.getRequestDescription());
        sysOperationLog.setOperatorId(req.getOperatorId());
        sysOperationLog.setIsDeleted(YesNoEnum.NO.getCode());
        sysOperationLogMapper.insertSysOperationLog(sysOperationLog);
    }

    @Override
    public PaginationResponse<PageOperationLogResp> pageQueryOperationLogs(PageOperationLogReq req) {
        // 组装查询条件中的操作人id
        if (StringUtils.isNotBlank(req.getOperatorNickname())) {
            List<SysUser> operators = sysUserFacade.fuzzySearchSysUsersByNickname(req.getOperatorNickname());
            req.setOperatorIds(CollectionUtils.isEmpty(operators) ?
                    null :
                    operators.stream().map(SysUser::getId).collect(Collectors.toList()));
        }

        List<SysOperationLog> sysOperationLogs = sysOperationLogMapper.pageQuerySysOperationLogs(req);
        if (CollectionUtils.isEmpty(sysOperationLogs)) {
            return PaginationResponse.get(Collections.emptyList(), req);
        }

        // 获取操作人的id对应昵称映射
        Map<Long, String> operatorId2NicknameMap = Maps.newHashMap();
        List<SysUser> operators = sysUserFacade.searchSysUsersByIds(
                sysOperationLogs.stream().map(SysOperationLog::getOperatorId).collect(Collectors.toList()));
        if (CollectionUtils.isNotEmpty(operators)) {
            operatorId2NicknameMap = operators.stream().collect(Collectors.toMap(SysUser::getId, SysUser::getUserNickname));
        }

        List<PageOperationLogResp> result = Lists.newArrayList();
        for (SysOperationLog sysOperationLog : sysOperationLogs) {
            PageOperationLogResp resp = new PageOperationLogResp();
            resp.setId(String.valueOf(sysOperationLog.getId()));
            resp.setTraceId(sysOperationLog.getTraceId());
            resp.setUri(sysOperationLog.getUri());
            resp.setParam(sysOperationLog.getParam());
            resp.setStartTime(sysOperationLog.getStartTime());
            resp.setConsumeTime(sysOperationLog.getConsumeTime());
            resp.setRequestDescription(sysOperationLog.getRequestDescription());
            if (Objects.isNull(sysOperationLog.getOperatorId())) {
                resp.setOperatorNickname("未登录");
            } else {
                resp.setOperatorId(String.valueOf(sysOperationLog.getOperatorId()));
                resp.setOperatorNickname(operatorId2NicknameMap.getOrDefault(
                        sysOperationLog.getOperatorId(), "该用户已不存在"));
            }
            result.add(resp);
        }

        return PaginationResponse.get(result, req);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void clearOutdatedTraceLogs() {
        // 将当前时间向前 14 天作为截止时间
        Date date = new Date(new Date().getTime() - 14 * 24 * 60 * 60 * 1000);
        sysTraceLogMapper.clearHistoricalAccumulationSysLog(date);
        logger.info("清理历史堆积的链路追踪日志完成, 本次清理的日志截止时间为：{}",
                DateUtils.Date2Str(date, YMD_HMS_MS_PATTERN));
    }

}
